#include <QRegularExpression>
#include "tcpclient.h"

TcpClient::TcpClient(QObject* parent, const QString& url) : QObject(parent) {
    this->setUrl(url);
}

TcpClient::~TcpClient() {
    this->freeSocket();
}

bool TcpClient::setUrl(const QString& url) {
    QUrl parsedUrl(url);
    this->host = parsedUrl.host();
    this->path = parsedUrl.path();
    this->port = parsedUrl.port();
    if (this->port == -1) {
        QString scheme = parsedUrl.scheme();
        if (scheme == "https")
            this->port = 443;
        else if (scheme == "http")
            this->port = 80;
        else
            return false;
    }
    return true;
}

bool TcpClient::initSocket() {
    if (this->socket != nullptr)
        this->freeSocket();
    this->socket = new QTcpSocket();
    connect(this->socket, &QTcpSocket::readyRead, this, &TcpClient::slot_readyRead);
    connect(this->socket, &QTcpSocket::disconnected, this, &TcpClient::slot_disconnected);
    this->socket->connectToHost(this->host, this->port);
    if (!this->socket->waitForConnected()) {
        this->freeSocket();
        return false;
    }
    return true;
}

bool TcpClient::postRequest(const QByteArray& postData) {
    if (this->socket == nullptr) {
        if (!this->initSocket())
            return false;
    }
    QByteArray request;
    request.append("POST " + this->path.toUtf8() + " HTTP/1.1\r\n");
    request.append("Host: " + this->host.toUtf8() + "\r\n");
    request.append("Content-Type: application/json\r\n");
    request.append("Content-Length: " + QString::number(postData.size()).toUtf8() + "\r\n");
    request.append("\r\n");
    request.append(postData);
    this->socket->write(request);
    if (!this->socket->waitForBytesWritten())
        return false;
    return true;
}

void TcpClient::freeSocket() {
    if (this->socket != nullptr) {
        if (this->socket->isOpen()) {
            if (this->socket->state() == QTcpSocket::ConnectedState) {
                this->socket->disconnectFromHost();
                if (!this->socket->waitForDisconnected(3000))
                    this->socket->abort();
            }
            this->socket->close();
        }
        delete this->socket;
        this->socket = nullptr;
    }
}

void TcpClient::slot_readyRead() {
    QByteArray response = this->socket->readAll();
    
    QByteArray endFlag = QString("0\r\n\r\n").toUtf8();
    bool isFinalResponse = false;
    if (response.endsWith(endFlag)) {
        if (response.length() == endFlag.length()) {
            emit signal_finished("");
            return;
        }
        isFinalResponse = true;
    }

    int headerEnd = response.indexOf("\r\n\r\n") + 4;
    
    if (headerEnd == 3) {
        emit signal_response(response);
        return;
    }
    
    QByteArray header = response.left(headerEnd);
    QByteArray body = response.mid(headerEnd);
    
    QRegularExpression re("Content-Length: (\\d+)");
    QRegularExpressionMatch match = re.match(header);
    if (match.hasMatch()) {
        int contentLength = match.captured(1).toInt();
        if (body.size() >= contentLength) {
            emit signal_finished(body);
            return;
        }
    } else if (isFinalResponse) {
        emit signal_finished(body);
        return;
    }
    emit signal_response(body);
}

void TcpClient::slot_disconnected() {
    this->freeSocket();
}
